﻿namespace WebPacker.Tests.Packs
{
	using System;
	using NUnit.Framework;
	using WebPacker.Filters;
	using WebPacker.Packs;
	using WebPacker.Packs.Resources;
	using WebPacker.VersionGenerators;

	[TestFixture]
	public class PackCollectionTest
	{
		[Test]
		public void AddNullTest()
		{
			var collection = new PackCollection();
			Assert.Throws<ArgumentNullException>(() => collection.Add(null));
		}

		[Test]
		public void AddTest()
		{
			var collection = new PackCollection();
			collection.Add(GetPack(PackType.JavaScript, "pack1"));
			Assert.AreEqual(1, collection.Count);
		}

		[Test]
		public void AddInvariantTest()
		{
			var collection = new PackCollection();
			collection.Add(GetPack(PackType.JavaScript, "pack1"));
			collection.Add(GetPack(PackType.JavaScript, "PACK1"));
			Assert.AreEqual(2, collection.Count);
		}

		[Test]
		public void AddRangeTest()
		{
			var collection = new PackCollection();
			var packs = GetTestPacks();
			collection.AddRange(packs);
			Assert.AreEqual(packs.Length, collection.Count);
		}

		[Test]
		public void AddComplexTest()
		{
			var collection = new PackCollection();
			collection.Add(GetPack(PackType.JavaScript, "pack1"));
			collection.Add(GetPack(PackType.Css, "pack1"));
			collection.Add(GetPack(PackType.JavaScript, "pack2"));
			Assert.AreEqual(3, collection.Count);
		}

		[Test]
		public void AddUniqueConstraintTest()
		{
			var collection = new PackCollection();
			collection.Add(GetPack(PackType.Css, "pack1"));
			Assert.Throws<ArgumentException>(() => collection.Add(GetPack(PackType.Css, "pack1")));
			Assert.AreEqual(1, collection.Count);
		}

		[Test]
		public void GetItemTest()
		{
			var packs = GetTestPacks();
			var collection = new PackCollection();
			collection.AddRange(packs);

			foreach (var pack in packs)
			{
				Assert.AreSame(pack, collection.GetItem(pack.PackType, pack.Name));
			}
		}

		[Test]
		public void ContainsTest()
		{
			var packs = GetTestPacks();
			var collection = new PackCollection();
			collection.AddRange(packs);

			foreach (var pack in packs)
			{
				Assert.IsTrue(collection.Contains(pack.PackType, pack.Name));
			}
		}

		[Test]
		public void TryGetItemTest()
		{
			var packs = GetTestPacks();
			var collection = new PackCollection();
			collection.AddRange(packs);

			foreach (var expected in packs)
			{
				IPack actual;
				Assert.IsTrue(collection.TryGetItem(expected.PackType, expected.Name, out actual));
				Assert.AreSame(expected, actual);
			}
		}

		[Test]
		public void GetItemFailedTest(
			[Values(PackType.Css, PackType.JavaScript)]
			PackType packType,
			[Values("unknown1", "JS1")]
			string packName)
		{
			var packs = GetTestPacks();
			var collection = new PackCollection();
			collection.AddRange(packs);
			Assert.Throws<ArgumentException>(() => collection.GetItem(packType, packName));
		}

		[Test]
		public void TryGetItemFailedTest(
			[Values(PackType.Css, PackType.JavaScript)]
			PackType packType,
			[Values("CSS1", "JS1")]
			string packName)
		{
			var packs = GetTestPacks();
			var collection = new PackCollection();
			collection.AddRange(packs);
			IPack actual;
			Assert.IsFalse(collection.TryGetItem(packType, packName, out actual));
			Assert.IsNull(actual);
		}

		[Test]
		public void ContainsFailedTest(
			[Values(PackType.Css, PackType.JavaScript)]
			PackType packType,
			[Values("CSS1", "JS1")]
			string packName)
		{
			var packs = GetTestPacks();
			var collection = new PackCollection();
			collection.AddRange(packs);
			Assert.IsFalse(collection.Contains(packType, packName));
		}

		[Test]
		public void RemoveTest()
		{
			var collection = new PackCollection();
			collection.Add(GetPack(PackType.Css, "pack1"));
			Assert.IsTrue(collection.Remove(PackType.Css, "pack1"));
			Assert.AreEqual(0, collection.Count);
		}

		[Test]
		public void RemoveFailedTest()
		{
			var collection = new PackCollection();
			collection.Add(GetPack(PackType.Css, "pack1"));
			Assert.IsFalse(collection.Remove(PackType.JavaScript, "pack1"));
			Assert.AreEqual(1, collection.Count);
		}

		[Test]
		public void RemoveSameTest()
		{
			var collection = new PackCollection();
			var pack = GetPack(PackType.Css, "pack1");
			collection.Add(pack);
			Assert.IsTrue(collection.Remove(pack));
			Assert.AreEqual(0, collection.Count);
		}

		[Test]
		public void RemoveSameFailedTest()
		{
			var collection = new PackCollection();
			collection.Add(GetPack(PackType.Css, "pack1"));
			Assert.IsFalse(collection.Remove(GetPack(PackType.Css, "pack1")));
			Assert.AreEqual(1, collection.Count);
		}

		private Pack[] GetTestPacks()
		{
			return new Pack[]
			{
				GetPack(PackType.Css, "css1"),
				GetPack(PackType.JavaScript, "js1"),
				GetPack(PackType.JavaScript, "js2"),
				GetPack(PackType.Css, "css2")
			};
		}

		private Pack GetPack(PackType packType, string packName)
		{
			var resources = new IResource[] { new ContentResource("res") };
			return new Pack(packType, packName, resources, new TestFilter(packType));
		}
	}
}
